package com.ruoyi.web.test;

import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelImageExtractor;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;

/**
 * Excel宏测试控制器
 *
 * 提供Web接口来测试Excel宏功能
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/test/excel/macro")
public class ExcelMacroTestController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(ExcelMacroTestController.class);

    /**
     * 上传带宏的Excel模板并写入测试数据
     *
     * 使用方法:
     * 1. 使用Postman或前端页面上传.xlsm文件
     * 2. 接口会向Excel写入测试数据
     * 3. 返回下载链接,下载后在Excel中查看二维码生成情况
     *
     * @param file Excel模板文件(.xlsm)
     * @param response HTTP响应
     * @return 处理结果
     */
    @PostMapping("/upload-and-write")
    public void uploadAndWriteData(@RequestParam("file") MultipartFile file,
                                   HttpServletResponse response) {
        if (file.isEmpty()) {
            try {
                response.getWriter().write("文件不能为空");
            } catch (IOException e) {
                log.error("响应失败", e);
            }
            return;
        }

        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".xlsm")) {
            try {
                response.getWriter().write("请上传.xlsm格式的Excel文件");
            } catch (IOException e) {
                log.error("响应失败", e);
            }
            return;
        }

        InputStream inputStream = null;
        OutputStream outputStream = null;
        Workbook workbook = null;

        try {
            inputStream = file.getInputStream();
            workbook = WorkbookFactory.create(inputStream);

            // 写入测试数据到第一个sheet
            Sheet dataSheet = workbook.getSheetAt(0);
            writeTestDataToSheet(dataSheet);

            // 设置响应头
            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            String fileName = "test_data_" + timestamp + ".xlsm";

            response.setContentType("application/vnd.ms-excel.sheet.macroEnabled.12");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    java.net.URLEncoder.encode(fileName, "UTF-8"));

            // 输出到响应流
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();

            log.info("Excel文件已生成并返回: {}", fileName);

        } catch (Exception e) {
            log.error("处理Excel失败", e);
            try {
                response.getWriter().write("处理失败: " + e.getMessage());
            } catch (IOException ex) {
                log.error("响应失败", ex);
            }
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    log.error("关闭工作簿失败", e);
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("关闭输入流失败", e);
                }
            }
        }
    }

    /**
     * 从Excel文件中提取二维码图片并返回Base64
     *
     * 使用场景:
     * 1. 上传Excel文件(可以是写入数据后的文件)
     * 2. 指定二维码所在的sheet索引
     * 3. 返回所有二维码的Base64编码
     *
     * @param file Excel文件(.xlsx或.xlsm)
     * @param sheetIndex sheet索引(默认1,即第二个sheet)
     * @return 包含所有二维码Base64的结果
     */
    @PostMapping("/extract-qrcodes")
    public AjaxResult extractQRCodes(
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "sheetIndex", defaultValue = "1") int sheetIndex) {

        if (file.isEmpty()) {
            return AjaxResult.error("文件不能为空");
        }

        File tempFile = null;
        try {
            // 保存临时文件
            tempFile = File.createTempFile("excel_qrcode_", ".xlsm");
            file.transferTo(tempFile);

            // 提取图片
            List<ExcelImageExtractor.ImageInfo> images =
                    ExcelImageExtractor.extractImagesFromSheet(tempFile.getAbsolutePath(), sheetIndex);

            if (images.isEmpty()) {
                return AjaxResult.warn("未在指定sheet中找到任何图片");
            }

            // 构造返回结果
            List<Map<String, Object>> result = new ArrayList<>();
            for (int i = 0; i < images.size(); i++) {
                ExcelImageExtractor.ImageInfo image = images.get(i);
                Map<String, Object> imageMap = new HashMap<>();
                imageMap.put("index", i);
                imageMap.put("row", image.getRow());
                imageMap.put("column", image.getColumn());
                imageMap.put("format", image.getFormat());
                imageMap.put("width", image.getWidth());
                imageMap.put("height", image.getHeight());
                imageMap.put("base64", image.getBase64());
                imageMap.put("dataSize", image.getData().length);
                result.add(imageMap);
            }

            Map<String, Object> data = new HashMap<>();
            data.put("total", images.size());
            data.put("sheetIndex", sheetIndex);
            data.put("images", result);

            log.info("成功提取{}个二维码图片", images.size());
            return AjaxResult.success("提取成功", data);

        } catch (Exception e) {
            log.error("提取二维码失败", e);
            return AjaxResult.error("提取失败: " + e.getMessage());
        } finally {
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete();
            }
        }
    }

    /**
     * 完整流程测试: 写入数据 -> 提取二维码
     *
     * 步骤:
     * 1. 上传带宏的Excel模板
     * 2. 写入测试数据
     * 3. 保存文件
     * 4. 提取二维码并返回Base64
     *
     * @param file Excel模板文件(.xlsm)
     * @param sheetIndex 二维码所在sheet索引
     * @return 包含二维码Base64的结果
     */
    @PostMapping("/full-test")
    public AjaxResult fullTest(
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "sheetIndex", defaultValue = "1") int sheetIndex) {

        if (file.isEmpty()) {
            return AjaxResult.error("文件不能为空");
        }

        File tempInputFile = null;
        File tempOutputFile = null;

        try {
            // 保存上传的模板文件
            tempInputFile = File.createTempFile("template_", ".xlsm");
            file.transferTo(tempInputFile);

            // 创建输出文件
            tempOutputFile = File.createTempFile("output_", ".xlsm");

            // 写入数据
            InputStream inputStream = new FileInputStream(tempInputFile);
            Workbook workbook = WorkbookFactory.create(inputStream);
            Sheet dataSheet = workbook.getSheetAt(0);
            writeTestDataToSheet(dataSheet);

            // 保存文件
            FileOutputStream outputStream = new FileOutputStream(tempOutputFile);
            workbook.write(outputStream);
            outputStream.close();
            workbook.close();
            inputStream.close();

            log.info("数据已写入Excel文件");

            // 等待一下确保文件完全写入
            Thread.sleep(500);

            // 提取二维码(注意:POI写入后宏不会自动执行,这里仅提取已有的图片)
            List<ExcelImageExtractor.ImageInfo> images =
                    ExcelImageExtractor.extractImagesFromSheet(tempOutputFile.getAbsolutePath(), sheetIndex);

            // 构造返回结果
            Map<String, Object> data = new HashMap<>();
            data.put("dataWritten", true);
            data.put("imageCount", images.size());
            data.put("sheetIndex", sheetIndex);

            if (!images.isEmpty()) {
                List<Map<String, Object>> imageList = new ArrayList<>();
                for (ExcelImageExtractor.ImageInfo image : images) {
                    Map<String, Object> imageMap = new HashMap<>();
                    imageMap.put("row", image.getRow());
                    imageMap.put("column", image.getColumn());
                    imageMap.put("format", image.getFormat());
                    imageMap.put("base64", image.getBase64());
                    imageList.add(imageMap);
                }
                data.put("images", imageList);
            } else {
                data.put("warning", "未找到二维码图片,可能宏尚未执行。请在Excel中打开文件并启用宏后重新提取。");
            }

            return AjaxResult.success("测试完成", data);

        } catch (Exception e) {
            log.error("完整测试失败", e);
            return AjaxResult.error("测试失败: " + e.getMessage());
        } finally {
            if (tempInputFile != null && tempInputFile.exists()) {
                tempInputFile.delete();
            }
            if (tempOutputFile != null && tempOutputFile.exists()) {
                tempOutputFile.delete();
            }
        }
    }

    /**
     * 生成测试数据的API接口
     *
     * @param sheetIndex 工作表索引(默认0)
     * @param startRow 起始行(默认1)
     * @param rowCount 数据行数(默认3)
     * @return 测试结果
     */
    @GetMapping("/generate-test-info")
    public AjaxResult generateTestInfo(
            @RequestParam(defaultValue = "0") int sheetIndex,
            @RequestParam(defaultValue = "1") int startRow,
            @RequestParam(defaultValue = "3") int rowCount) {

        String info = String.format(
                "测试配置:\n" +
                        "- 工作表索引: %d\n" +
                        "- 起始行: %d\n" +
                        "- 数据行数: %d\n\n" +
                        "使用说明:\n" +
                        "1. 准备一个带宏的Excel模板(.xlsm)\n" +
                        "2. 宏应该监听第一个sheet的数据变化\n" +
                        "3. 使用 /test/excel/macro/upload-and-write 接口上传模板\n" +
                        "4. 下载生成的Excel文件\n" +
                        "5. 在Excel中启用宏\n" +
                        "6. 检查第二个sheet是否生成了二维码\n" +
                        "7. 使用Ctrl+P查看打印预览",
                sheetIndex, startRow, rowCount
        );

        return AjaxResult.success(info);
    }

    /**
     * 写入测试数据到工作表
     *
     * @param sheet 工作表
     */
    private void writeTestDataToSheet(Sheet sheet) {
        // 测试数据
        Object[][] testData = {
                {"订单编号", "商品名称", "数量", "单价", "总价", "备注"},
                {"ORD20250116001", "测试商品A", 10, 99.50, 995.00, "二维码测试1"},
                {"ORD20250116002", "测试商品B", 5, 199.00, 995.00, "二维码测试2"},
                {"ORD20250116003", "测试商品C", 3, 299.99, 899.97, "二维码测试3"}
        };

        int startRow = 1; // 从第2行开始(索引1)

        for (int i = 0; i < testData.length; i++) {
            Row row = sheet.getRow(startRow + i);
            if (row == null) {
                row = sheet.createRow(startRow + i);
            }

            Object[] rowData = testData[i];
            for (int j = 0; j < rowData.length; j++) {
                Cell cell = row.getCell(j);
                if (cell == null) {
                    cell = row.createCell(j);
                }

                Object value = rowData[j];
                if (value instanceof String) {
                    cell.setCellValue((String) value);
                } else if (value instanceof Integer) {
                    cell.setCellValue((Integer) value);
                } else if (value instanceof Double) {
                    cell.setCellValue((Double) value);
                }
            }
        }

        log.info("已写入{}行测试数据到工作表: {}", testData.length, sheet.getSheetName());
    }
}
